home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** Routine demonstrating how to call MathLib functions that use 128 bit
- ** long doubles as arguments and return values.
- **
- ** by Mark Cookson, Apple Developer Technical Support
- **
- ** File: long_double.c
- **
- ** Copyright ©1996 Apple Computer, Inc.
- ** All rights reserved.
- **
- ** You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "Apple Sample
- ** Code" after having made changes. If you're going to re-distribute the
- ** source, we require that you make it clear in the source that the code
- ** was descended from Apple Sample Code, but that you've made changes.
- */
-
- /*
- This is for PowerPC only, and the assembly code at the end is PowerPC
- assembly. The MathLib library is a PowerPC only library.
-
- This code has been tested with Metrowerks Codewarrior 10 and produces
- the same result as standard code compiled with Mr. C (with the 128 bit
- long double option turned on).
-
- This code is needed to call the MathLib functions because the current
- Metrowerks compilers do not create a 128 bit long double, they create
- a 64 bit long double. All of the MathLib functions that require a long
- double expect a 128 bit long double and therefore do not produce the
- correct results when given a 64 bit long double.
-
- The callMathLib1ArgFcn routine takes three pointers, two pointers to
- long_doubles and one ProcPtr. The first pointer to a long_double is
- the argument, the second pointer to a long_double is the result, and
- the ProcPtr is the MathLib function to be called.
-
- The callMathLib2ArgFcn routine takes four pointers, three pointers to
- long_doubles and one ProcPtr. The first two pointers to long_double's
- are the first two arguments to the function to be called, the third pointer
- to a long_double is the result returned by the function to be called, and
- the ProcPtr is the MathLib function to be called (in this example the powl
- function).
-
- The callMathLibXArgFcn functions set up the floating point registers,
- call the MathLib function, and then return the results in the result
- structure.
-
- The callMathLibFcn can easily be modified to deal with other functions
- which don't take only long doubles or return something other than a
- long double, but that is left up to the reader.
-
- There are only 5 out of 46 functions in fp.h that these two routines
- don't cover.
- */
-
- #include <stdio.h>
- #include <fp.h>
-
- //what a real long double (double-double) looks like
- typedef struct long_double {
- double head;
- double tail;
- } long_double;
-
- //prototype for functions which will call the passed MathLib function the correct way
- //this function can work for any function that takes one long double and returns a long double
- asm void callMathLib1ArgFcn ( ProcPtr fcn, long_double *x, long_double *res );
-
- //this function can work for any function that takes two long doubles and returns a long double
- asm void callMathLib2ArgFcn ( ProcPtr fcn, long_double *x, long_double *y, long_double *res );
-
- void main (void) {
- long_double x,
- y,
- ldResult;
- double dResult;
-
- x.head = 3.141592653;
- x.tail = 0.0;
- y.head = 5.0;
- y.tail = 0.0;
- ldResult.head = 0.0;
- ldResult.tail = 0.0;
-
- callMathLib2ArgFcn ((ProcPtr)powl, &x, &y, &ldResult);
-
- //this is the correct conversion from a long double to a double
- //See page 5-7 of Inside Macintosh:PowerPC Numerics
- dResult = ldResult.head + ldResult.tail;
-
- printf ("The head is: %1.17e\nThe tail is: %1.17e\n", ldResult.head, ldResult.tail);
- printf ("The value of ldResult converted to a double is: %1.17e\n", dResult);
- }
-
- //This is PowerPC assembly for calling the PowerPC-only MathLib library.
- //These functions do the dirty work of setting things up for the call to the MathLib function.
- //This code is for ease of reading, not for speed.
- asm void callMathLib1ArgFcn ( ProcPtr fcn, long_double *x, long_double *res ) {
- fralloc //create a stack frame because we will be calling other functions
-
- lwz r8,x //put pointer to argument into register
-
- lfd fp1,0(r8) //put the real arguments in the fp registers
- lfd fp2,8(r8)
-
- lwz r12,fcn //put the address of the function to call in r12
- stw RTOC,20(SP) //setup the stack for the call
- lwz r0,0(r12)
- lwz RTOC,4(r12)
- mtctr r0
- bctrl //call the MathLib function
- lwz RTOC,20(SP) //restore our RTOC
-
- lwz r10,res //return our results in the res structure
- stfd fp1,0(r10) //this is the head of the result
- stfd fp2,8(r10) //this is the tail of the result
-
- frfree //clean up stack frame
- blr //back from whence we came
- }
-
- asm void callMathLib2ArgFcn ( ProcPtr fcn, long_double *x, long_double *y, long_double *res ) {
- fralloc //create a stack frame because we will be calling other functions
-
- lwz r8,x //put pointers to arguments into registers
- lwz r9,y
-
- lfd fp1,0(r8) //put the real arguments in the fp registers
- lfd fp2,8(r8)
- lfd fp3,0(r9)
- lfd fp4,8(r9)
-
- lwz r12,fcn //put the address of the function to call in r12
- stw RTOC,20(SP) //setup the stack for the call
- lwz r0,0(r12)
- lwz RTOC,4(r12)
- mtctr r0
- bctrl //call the MathLib function
- lwz RTOC,20(SP) //restore our RTOC
-
- lwz r10,res //return our results in the res structure
- stfd fp1,0(r10) //this is the head of the result
- stfd fp2,8(r10) //this is the tail of the result
-
- frfree //clean up stack frame
- blr //back from whence we came
- }
-
-